package de.wojenko.spe;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SplitPane;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.AnchorPane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;
import javafx.util.Callback;

import javax.xml.bind.JAXBException;

import de.wojenko.sps.BacklogItem;
import de.wojenko.sps.BacklogItemArtefact;
import de.wojenko.sps.ServiceProvider;
import de.wojenko.sps.SprintData;
import de.wojenko.sps.SprintDataExporter;

public class MainPaneController extends AnchorPane {

	private final Stage primaryStage;

	@FXML
	private ListView<BacklogItem> userStoryList;

	@FXML
	private SplitPane lists;

	@FXML
	private MenuBar mainMenu;

	@FXML
	private MenuItem importMenuItem;

	@FXML
	private MenuItem openMenuItem;

	@FXML
	private MenuItem saveMenuItem;

	@FXML
	private Menu exportMenu;

	private CardListPaneController uatListPane;
	private CardListPaneController taskListPane;

	private SprintDataHolder<BacklogItem> sprintDataHolder;

	private SprintDataExporter<BacklogItem>[] sprintDataExporter = ServiceProvider
			.getSprintDataExporter();

	private static class UserStoryListCell extends ListCell<BacklogItem> {
		private final MainPaneController controller;

		public UserStoryListCell(MainPaneController c) {
			controller = c;
		}

		@Override
		protected void updateItem(final BacklogItem item, boolean empty) {
			super.updateItem(item, empty);
			if (item != null) {
				setText(item.getName());
				setOnMouseClicked(new EventHandler<Event>() {
					@Override
					public void handle(Event event) {
						controller.selectUserStory(item);
					}
				});
			}
		}
	}

	public MainPaneController(Stage primaryStage) {
		this.primaryStage = primaryStage;
		FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
				"MainPane.fxml"));
		fxmlLoader.setRoot(this);
		fxmlLoader.setController(this);

		try {
			fxmlLoader.load();
		} catch (IOException exception) {
			throw new RuntimeException(exception);
		}

		uatListPane = new CardListPaneController();
		taskListPane = new CardListPaneController();
		uatListPane.setName("UATs");
		taskListPane.setName("Tasks");
		lists.getItems().addAll(uatListPane, taskListPane);

		mainMenu.setUseSystemMenuBar(true);

		importMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.I,
				KeyCombination.META_DOWN));
		openMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.O,
				KeyCombination.META_DOWN));
		saveMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.S,
				KeyCombination.META_DOWN));
		if (sprintDataExporter.length != 0) {
			exportMenu.setDisable(false);
			for (final SprintDataExporter<BacklogItem> exporter : sprintDataExporter) {
				MenuItem item = new MenuItem(exporter.getDescription());
				item.setOnAction(new EventHandler<ActionEvent>() {
					@Override
					public void handle(ActionEvent event) {
						exportBacklogArtefacts(exporter);
					}
				});
				exportMenu.getItems().add(item);
			}
		}
	}

	public void importSprint() {
		System.out.println("import");
		try {
			FileChooser fileChooser = new FileChooser();
			fileChooser.setTitle("Import sprint...");
			fileChooser.getExtensionFilters().add(
					new ExtensionFilter("Jira Exports", "*.xml"));
			fileChooser.setInitialDirectory(new File(System
					.getProperty("user.home")));
			File file = fileChooser.showOpenDialog(primaryStage);

			if (file != null) {
				SprintData<BacklogItem> sprint = ServiceProvider
						.getSprintDataImportService().importSprint(file);
				setSprintData(new SprintDataHolder<BacklogItem>(null, sprint));
			}
		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

	public void openSprint() {
		System.out.println("open");
		try {
			FileChooser fileChooser = new FileChooser();
			fileChooser.setTitle("Open sprint...");
			fileChooser.getExtensionFilters().add(
					new ExtensionFilter("Sprints", "*.sprint"));
			fileChooser.setInitialDirectory(new File(System
					.getProperty("user.home")));
			File file = fileChooser.showOpenDialog(primaryStage);

			if (file != null) {
				SprintData<BacklogItem> sprint = ServiceProvider
						.getSprintDataIOService().loadSprint(file);
				setSprintData(new SprintDataHolder<BacklogItem>(file, sprint));
			}
		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

	public void saveSprint() {
		System.out.println("save");
		if (this.sprintDataHolder.file == null) {
			saveSprintAs();
		} else {
			saveSprint(this.sprintDataHolder.file,
					this.sprintDataHolder.sprintData);
		}
	}

	public void saveSprintAs() {
		System.out.println("saveAs");
		FileChooser fileChooser = new FileChooser();
		fileChooser.setTitle("Save sprint...");
		fileChooser.setInitialFileName(sprintDataHolder.sprintData.getName()
				+ ".sprint");
		fileChooser.getExtensionFilters().add(
				new ExtensionFilter("Sprints", "*.sprint"));
		fileChooser.setInitialDirectory(new File(System
				.getProperty("user.home")));
		File file = fileChooser.showSaveDialog(primaryStage);

		if (file != null) {
			saveSprint(file, sprintDataHolder.sprintData);
		}
	}

	public void exportBacklogArtefacts(SprintDataExporter<BacklogItem> exporter) {
		try {
			System.out.println("export");
			FileChooser fileChooser = new FileChooser();
			fileChooser.setTitle("Save sprint...");
			fileChooser.setInitialFileName(sprintDataHolder.sprintData.getName()
					+ ".pdf");
			fileChooser.getExtensionFilters().add(
					new ExtensionFilter("PDF", "*.pdf"));
			fileChooser.setInitialDirectory(new File(System
					.getProperty("user.home")));
			final File file = fileChooser.showSaveDialog(primaryStage);
			exporter.exportSprint(file, sprintDataHolder.sprintData);
			if (file.isFile()) {
//				new Thread(new Runnable() {
//					@Override
//					public void run() {
//						try {
//							Desktop.getDesktop().open(file);
//						} catch (IOException e) {
//							e.printStackTrace();
//						}
//					}
//				}).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void saveSprint(File file, SprintData<BacklogItem> sprint) {
		try {
			ServiceProvider.getSprintDataIOService().saveSprint(file, sprint);
		} catch (JAXBException e) {
			e.printStackTrace();
		}
	}

	private void setSprintData(SprintDataHolder<BacklogItem> sprintDataHolder) {
		this.sprintDataHolder = sprintDataHolder;
		final MainPaneController c = this;
		ObservableList<BacklogItem> observableUserStoryList = FXCollections
				.observableArrayList();
		observableUserStoryList.addAll(sprintDataHolder.sprintData
				.getBacklogItemList());
		userStoryList.itemsProperty().set(observableUserStoryList);
		userStoryList
				.setCellFactory(new Callback<ListView<BacklogItem>, ListCell<BacklogItem>>() {
					@Override
					public ListCell<BacklogItem> call(
							ListView<BacklogItem> param) {
						return new UserStoryListCell(c);
					}
				});

		selectUserStory(sprintDataHolder.sprintData.getBacklogItemList().get(0));
	}

	private void selectUserStory(final BacklogItem userStory) {
		taskListPane.setListController(new BacklogItemArtefactListController() {

			@Override
			public String getName() {
				return userStory.getName();
			}

			@Override
			public void removeArtefact(BacklogItemArtefact arg) {
				userStory.getTaskList().remove(arg);
			}

			@Override
			public List<BacklogItemArtefact> getArtefacts() {
				return userStory.getTaskList();
			}

			@Override
			public BacklogItemArtefact createNewArtefact() {
				return userStory.addTask();
			}
		});
		uatListPane.setListController(new BacklogItemArtefactListController() {

			@Override
			public String getName() {
				return userStory.getName();
			}

			@Override
			public void removeArtefact(BacklogItemArtefact arg) {
				userStory.getAcceptanceCriteriaList().remove(arg);
			}

			@Override
			public List<BacklogItemArtefact> getArtefacts() {
				return userStory.getAcceptanceCriteriaList();
			}

			@Override
			public BacklogItemArtefact createNewArtefact() {
				return userStory.addAcceptanceCriteria();
			}
		});
	}
}
